home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 10
/
AACD 10.iso
/
AACD
/
Magazine
/
Online
/
httpproxy
/
src
/
httpfetch.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-08-20
|
9KB
|
393 lines
/*(( "Header" */
/*
* $Id: httpfetch.c,v 1.5 1996/08/11 22:25:15 mshopf Exp mshopf $
*
* (c) 1995-96 Matthias Hopf
*
* The usual fetchurl tool, with some extensions for httpproxy.
*/
/*
* $Log: httpfetch.c,v $
* Revision 1.5 1996/08/11 22:25:15 mshopf
* reworked debug messages.
*
* Revision 1.4 1996/07/17 16:42:42 mshopf
* small bug fix.
*
* Revision 1.3 1996/06/03 04:13:31 mshopf
* support for net errors.
*
* Revision 1.2 1996/05/15 01:07:58 mshopf
* small bug fix.
*
* Revision 1.1 1996/04/16 04:39:29 mshopf
*/
/*)) */
/*(( "Includes & Konstanten" */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include "net.h"
#include "debug.h"
#define BUFSIZE 1024 /* don't make this one too large (it's on the stack) */
#define MAX_HOSTNAMELEN 128 /* including port number specifiers */
#define MAX_URLLEN 1024 /* maximum size of URL request */
#define MAX_OVERHEAD 128 /* maximum size of protocol overhead */
#define DEFAULT_HTTPPORT 80
#define DEFAULT_PROXYPORT 8080
#define DEFAULT_RETRIES 1
#define DEFAULT_HEADER FALSE
#define DEFAULT_SERVICE FALSE
/*)) */
/*(( "Global Variables" */
long __oslibversion = 37;
const char *Version = "httpfetch/1.0";
#ifdef DEBUG
int DebugLevel = -1;
#endif
static netmethods_t *Net = NULL;
static int InSocket = -1;
static FILE *OutStream = stdout;
static struct RDArgs *RDArgs = NULL;
static char *Template = "URL/A,FROM=PROXY/K,TO=FILE,RETRIES=RETRY/N/K,HEADER=FULL/S,SERVICE/S,DISCARD=QUIET/S";
#define arg_url ((char *) (RetArray[0]))
#define arg_from ((char *) (RetArray[1]))
#define arg_to ((char *) (RetArray[2]))
#define arg_retries (RetArray[3] ? *((long *) (RetArray[3])) : DEFAULT_RETRIES)
#define arg_header ((long) (RetArray[4]))
#define arg_service ((long) (RetArray[5]))
#define arg_discard ((long) (RetArray[6]))
/*)) */
/*(( "ExitAll () / ExitErr ()" */
/* Close everything and return */
void ExitAll (int Ret)
{
if (Net && InSocket >= 0)
Net->close (InSocket);
InSocket = -1;
if (Net)
Net->exit ();
Net = NULL;
if (OutStream && OutStream != stdout)
fclose (OutStream);
OutStream = NULL;
if (RDArgs)
FreeArgs (RDArgs);
RDArgs = NULL;
exit (Ret);
}
/* Print errormessage and exit with 10 */
void ExitErr (const char *Msg)
{
if (errno)
{
if (Net)
fprintf (stderr, "%s: %s\n", Msg, Net->strerror (errno));
else
perror (Msg);
}
else
fprintf (stderr, "%s\n", Msg);
ExitAll (10);
}
/*)) */
/*(( "SendRequest ()" */
/* send request to Socket fd */
int SendRequest (int Fd, char *Req)
{
int Len;
Len = strlen (Req);
return (Net->write (Fd, Req, Len) == Len);
}
/*)) */
/*(( "SkipHeader ()" */
/* skip header data */
int SkipHeader (int Fd)
{
char Buffer [BUFSIZE+1];
char *c, *Pos;
int i;
Pos = Buffer;
for (;;)
{
/* read partial header */
if ( (i = Net->read (Fd, Pos, (int) (BUFSIZE - (Buffer - Pos)))) <= 0)
return FALSE;
Pos [i] = '\0';
/* check for header end and flush the rest into the output stream */
if ( (c = strstr (Buffer, "\r\n\r\n")) || (c = strstr (Buffer, "\n\r\n\r")) )
{
if (OutStream && Pos + i - c - 4 > 0)
return ((int) fwrite (c + 4, (size_t) (Pos + i - c - 4), 1, OutStream)); /* fwrite returns number of blocks=1 on success... */
return TRUE;
}
if ( (c = strstr (Buffer, "\r\r")) || (c = strstr (Buffer, "\n\n")) )
{
if (OutStream && Pos + i - c - 2 > 0)
return ((int) fwrite (c + 2, (size_t) (Pos + i - c - 2), 1, OutStream)); /* fwrite returns number of blocks=1 on success... */
return TRUE;
}
/* header not yet done - check end and skip back until we're save for flushing */
if (Pos [i-1] != '\r' && Pos [i-1] != '\n')
Pos = Buffer;
else
{
c = &Pos [i-2];
while (c >= Buffer)
if (*c != '\r' && *c != '\n')
break;
else
c--;
/* move remaining '\n' and '\r's to beginning of buffer */
memmove (Buffer, c + 1, (size_t) (Pos + i - c - 1));
Pos = Buffer + (Pos + i - c - 1);
}
}
/* NOTREACHED */
}
/*)) */
/*(( "ReceiveData ()" */
/* save received data */
int ReceiveData (int Fd)
{
char Buffer [BUFSIZE];
int i;
for (;;)
{
if ( (i = Net->read (Fd, Buffer, BUFSIZE)) <= 0)
return (i < 0 ? FALSE : TRUE);
if (OutStream)
if (fwrite (Buffer, i, 1, OutStream) != 1)
return FALSE;
}
/* NOTREACHED */
}
/*)) */
/*(( "MakeRequest ()" */
void MakeRequest (char *Req, char *Url)
{
int Len;
Len = strlen (Req);
Req += Len;
Len += strlen (Url);
if (Len > MAX_URLLEN)
ExitErr ("URL too long error");
strcpy (Req, Url);
Req += strlen (Req);
sprintf (Req, " HTTP/1.0\r\nUser-Agent: %s\r\nAccept: */*\r\n\r\n", Version);
}
/*)) */
/*(( "MakeService ()" */
/* Make a httpproxy service request */
void MakeService (char *Req, char *Service)
{
int Len;
Len = strlen (Req);
Req += Len; /* skip protocol part and GET command */
Len += strlen (Service);
if (Len > MAX_URLLEN)
ExitErr ("Service too long error");
strcpy (Req, "http://proxy.../");
Req += 16;
strcpy (Req, Service);
Req += strlen (Req);
sprintf (Req, " HTTP/1.0\r\nUser-Agent: %s\r\nAccept: */*\r\n\r\n", Version);
}
/*)) */
/*(( "Action ()" */
/* Interprete Arguments */
/* RetArray has to be exactly written like this in order to have the arg_* macros working */
void Action (long *RetArray)
{
static char Request [MAX_URLLEN + MAX_OVERHEAD];
char Host [MAX_HOSTNAMELEN];
int Port = DEFAULT_HTTPPORT;
char *c;
int i;
Host [0] = '\0';
if (arg_to && arg_discard)
ExitErr ("don't specify both TO=FILE and DISCARD=QUIET");
/* - destination file */
if (arg_to)
if (! (OutStream = fopen (arg_to, "wb+")))
ExitErr ("can't open file");
if (arg_discard)
OutStream = NULL;
/* - proxy host, url and service */
if (arg_from)
{ /* get in proxy mode */
Port = DEFAULT_PROXYPORT;
strncpy (Host, arg_from, MAX_HOSTNAMELEN-1);
Host [MAX_HOSTNAMELEN-1] = '\0';
if ( (c = strchr (Host, ':')) )
{
*c = '\0';
Port = atoi (c+1);
}
strcpy (Request, "GET ");
if (arg_service)
MakeService (Request, arg_url);
else
MakeRequest (Request, arg_url);
}
else
{
if (! arg_service)
{
/* check protocol name for 'http://' */
if (strncmp (arg_url, "http://", 7) != 0)
ExitErr ("invalid URL");
strcpy (Request, "GET ");
/* now get host name and port */
strncpy (Host, arg_url + 7, MAX_HOSTNAMELEN-1); /* ok, that's too much, but who cares */
Host [MAX_HOSTNAMELEN-1] = '\0';
if ( (c = strchr (Host, '/')) ) /* get hostname and port */
*c = '\0';
if ( (c = strchr (Host, ':')) )
{
*c = '\0';
Port = atoi (c+1);
}
if (Host [0] == '\0') /* no host??? */
ExitErr ("invalid URL");
/* get local object name */
if ( (c = strchr (arg_url + 7, '/')) )
MakeRequest (Request, c);
else
MakeRequest (Request, "/");
}
else
{
strcpy (Host, "localhost"); /* on service we'll address our local proxy */
Port = DEFAULT_PROXYPORT;
strcpy (Request, "GET ");
MakeService (& Request [4], arg_url);
}
}
for (i = 0; i < arg_retries; i++)
{
if (i)
Delay (50); /* one second delay after first try */
if ( (InSocket = Net->open (Host, Port)) < 0)
continue;
if (! SendRequest (InSocket, Request))
{
Net->close (InSocket);
InSocket = -2;
continue;
}
break;
}
switch (InSocket) {
case -1:
ExitErr ("can't contact host");
case -2:
ExitErr ("failed sending request");
}
if (OutStream && ! arg_header)
if (! SkipHeader (InSocket))
ExitErr ("failed while receiving header");
if (! ReceiveData (InSocket))
ExitErr ("failed while receiving data");
Net->close (InSocket);
InSocket = -1;
}
/*)) */
/*(( "main ()" */
/* main function */
void main (int argc, char *argv[])
{
netmethods_t *NetList[] = { &NetAmiTCP, &NetAS225, NULL }; /* all available net protocolls */
netmethods_t **TestNet;
long RetArray[] = { 0, 0, 0, 0, 0, 0, 0 };
/* get net handler */
for (TestNet = NetList; (Net = *TestNet); TestNet++)
if (Net->init (TRUE)) /* check for opening in blocking mode */
break;
if (! Net)
{
fprintf (stderr, "Couldn't open network protocol handler - perhaps the network stack is not running.\n"
"Available network protocol handlers:\n");
for (TestNet = NetList; (Net = *TestNet); TestNet++)
fprintf (stderr, "%s\n", Net->Descr);
ExitAll (20);
}
/* Get arguments */
if (! (RDArgs = ReadArgs (Template, RetArray, NULL)))
{
fprintf (stderr, "%s\n"
"\tURL: The URL to be retrieved.\n"
"\tFROM: Proxy host (and :port) to be used for fetching.\n"
"\tTO: Filename for the resulting document.\n"
"\tRETRIES: The number of retries after one second delay each.\n"
"\tHEADER: The response header is saved, too.\n"
"\tSERVICE: Url specifies the proxy service to be done.\n"
"\tDISCARD: Discard received data.\n",
Template);
ExitAll (10);
}
Action (RetArray);
ExitAll (0);
}
/*)) */